<?php

require_once(__DIR__ . '/IRenderer.php');

/**
 * php模板引擎
 * @author ice.deng <ice.deng@qq.com>
 */
class PhpRenderer implements IRenderer
{
    /**
     * 模板路径
     * @var string
     */
    protected $templatePath;

    /**
     * 属性值
     * @var array
     */
    protected $attributes;

    /**
     * PhpRenderer constructor.
     * @param string $templatePath
     * @param array $attributes
     */
    public function __construct($templatePath = "", $attributes = [])
    {
        $this->templatePath = $templatePath;
        $this->attributes = $attributes;
    }

    /**
     * Render a template
     * @param $template
     * @param array $data
     * @return mixed
     */
    public function render($template, array $data = [])
    {
        $output = $this->fetch($template, $data);
        return $output;
    }

    /**
     * Get the attributes for the renderer
     *
     * @return array
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * Set the attributes for the renderer
     *
     * @param array $attributes
     */
    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
    }

    /**
     * Add an attribute
     *
     * @param $key
     * @param $value
     */
    public function addAttribute($key, $value)
    {
        $this->attributes[$key] = $value;
    }

    /**
     * Retrieve an attribute
     *
     * @param $key
     * @return mixed
     */
    public function getAttribute($key)
    {
        if (!isset($this->attributes[$key])) {
            return false;
        }

        return $this->attributes[$key];
    }

    /**
     * Get the template path
     *
     * @return string
     */
    public function getTemplatePath()
    {
        return $this->templatePath;
    }

    /**
     * Set the template path
     *
     * @param string $templatePath
     */
    public function setTemplatePath($templatePath)
    {
        $this->templatePath = $templatePath;
    }

    /**
     * Renders a template and returns the result as a string
     *
     * cannot contain template as a key
     *
     * throws RuntimeException if $templatePath . $template does not exist
     *
     * @param $template
     * @param array $data
     *
     * @return mixed
     *
     * @throws InvalidArgumentException
     * @throws RuntimeException
     */
    public function fetch($template, array $data = [])
    {
        if (isset($data['template'])) {
            throw new InvalidArgumentException("Duplicate template key found");
        }

        if (!is_file($this->templatePath . $template)) {
            throw new RuntimeException("View cannot render `$template` because the template does not exist");
        }

        $data = array_merge($this->attributes, $data);

        ob_start();
        $this->protectedIncludeScope($this->templatePath . $template, $data);
        $output = ob_get_clean();

        return $output;
    }

    /**
     * @param string $template
     * @param array $data
     */
    protected function protectedIncludeScope($template, array $data)
    {
        extract($data);
        include $template;
    }

    /**
     * 获取对象的属性值
     *
     * php魔术方法,在未找到属性时会调用此方法
     * @param string $name 属性明
     * @return mixed 属性的值
     * @throws \Exception 如果属性未找到
     * @throws \Exception 如果属性为只写
     * @see __set()
     */
    public function __get($name)
    {
        return $this->getAttribute($name);
    }

    /**
     * 设置对象属性值
     *
     * php魔术方法,在未找到属性时会调用此方法
     * @param string $name 属性名称或事件名称
     * @param mixed $value 设置的属性值
     * @throws \Exception 属性未找到
     * @throws \Exception 属性为只读
     * @see __get()
     */
    public function __set($name, $value)
    {
        $this->addAttribute($name, $value);
    }
}